package com.inspur.cloud.service.dataspace;

import com.inspur.cloud.entity.dataspace.*;
import com.inspur.cloud.entity.dataspace.ao.auth.AuthInfoAO;
import com.inspur.cloud.entity.dataspace.ao.auth.ResourceAuthInfoAO;
import com.inspur.cloud.entity.dataspace.ao.user.UserAO;
import com.inspur.cloud.entity.dataspace.dto.ResourceCommonDTO;
import com.inspur.cloud.entity.dataspace.vo.auth.AuthInfoVO;
import com.inspur.cloud.entity.dataspace.vo.auth.AuthUpdateVO;
import com.inspur.cloud.enums.PermissionEnum;
import com.inspur.cloud.enums.RoleEnum;
import com.inspur.cloud.exception.ApiException;
import com.inspur.cloud.security.AuthorizationHelper;
import com.inspur.cloud.util.TConstants;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AuthService {

    @Autowired
    private UserResRelationSerivce userResRelationSerivce;
    @Autowired
    private HdfsResourceService hdfsResourceService;
    @Autowired
    private HiveResourceService hiveResourceService;
    @Autowired
    private HbaseResourceService hbaseResourceService;
    @Autowired
    private YarnResourceService yarnResourceService;
    @Autowired
    private KafkaResourceService kafkaResourceService;
    @Autowired
    private UserManagerService userManagerService;
    @Autowired
    private RangerService rangerService;

    /**
     * 获取资源的权限信息
     *
     * @param id   资源id
     * @param type 资源类型
     * @return
     */
    public ResourceAuthInfoAO getInfo(Integer id, String type) {
        ResourceAuthInfoAO result = new ResourceAuthInfoAO();
        UserEntity user = AuthorizationHelper.getUser();
        //获取当前用户的资源权限
        Integer resourceId = id;
        UserResourceRelationEntity userResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceId, user.getId(), type);
        //需要向父节点寻找权限
        ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
        while (userResourceRelation == null) {
            resourceCommon = getResourceCommon(resourceCommon.getParentId(), type);
            if (resourceCommon == null) {
                break;
            }
            userResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceCommon.getId(), user.getId(), type);
        }
        if (userResourceRelation == null || StringUtils.isEmpty(userResourceRelation.getAuthor())) {
            throw new ApiException("该用户无权这么做");
        }
        resourceCommon = getResourceCommon(resourceId, type);
        result.setCurrentUserAuth(userResourceRelation.getAuthor().toLowerCase().split("\\|"));
        result.setResourceContent(userResourceRelation.getResourceContent());
        result.setResourceType(type);
        result.setResourceId(id);
        List<UserResourceRelationEntity> list = userResRelationSerivce.findByResourceIdAndResourceType(id, type);
        List<AuthInfoAO> authList = new ArrayList<>();
        for (UserResourceRelationEntity tmp : list) {
            UserEntity tmpUser = userManagerService.findUserById(tmp.getUserId());
            if (!checkUpdateAuth(user, tmpUser, resourceCommon)) {
                continue;
            }
            AuthInfoAO authInfo = new AuthInfoAO();
            String auth = tmp.getAuthor();
            if (StringUtils.isEmpty(auth)) {
                authInfo.setAuth(null);
            } else {
                authInfo.setAuth(tmp.getAuthor().toLowerCase().split("\\|"));
            }
            authInfo.setUserId(tmp.getUserId());
            authInfo.setId(tmp.getId());
            authInfo.setUserName(tmpUser.getName());
            authInfo.setRole(tmpUser.getRole());
            authList.add(authInfo);
        }
        result.setAuthList(authList);
        return result;
    }

    /**
     * 更新资源权限
     *
     * @param authUpdate 更新权限参数
     */
   // @Transactional
    public void updateInfo(AuthUpdateVO authUpdate) {
        Integer resourceId = authUpdate.getId();
        String type = authUpdate.getType();

        UserEntity currentUser = AuthorizationHelper.getUser();
        boolean isAdmin = AuthorizationHelper.isAdmin(currentUser);
        //获取当前用户的资源权限
        UserResourceRelationEntity currentUserResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceId, currentUser.getId(), type);

        ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
        while (currentUserResourceRelation == null) {
            resourceCommon = getResourceCommon(resourceCommon.getParentId(), type);
            if (resourceCommon == null) {
                break;
            }
            currentUserResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceCommon.getId(), currentUser.getId(), type);
        }
        resourceCommon = getResourceCommon(resourceId, type);
        if (currentUserResourceRelation == null || StringUtils.isEmpty(currentUserResourceRelation.getAuthor())) {
            if (!isAdmin) {
                throw new ApiException("该用户无权这么做");
            }
        }
        String currentUserAuthor;
        //hdfs的第一层资源允许admin权限
        if (type.equalsIgnoreCase(TConstants.COMPONENT_HDFS) && resourceCommon.getLevel() == 1 && isAdmin) {
            currentUserAuthor = PermissionEnum.getAllPermissionByType(1);
        } else {
            currentUserAuthor = currentUserResourceRelation.getAuthor();
        }
        List<UserResourceRelationEntity> oldList = userResRelationSerivce.findByResourceIdAndResourceType(resourceId, type);
        List<AuthInfoVO> newList = authUpdate.getAuthList();
        for (AuthInfoVO newAuth : newList) {
            //如果新增权限，当前用户是否有此权限，如果没有就不能修改
            if (!StringUtils.isEmpty(newAuth.getAuth())) {
                boolean isLegal = true;
                for (String tmpStr : newAuth.getAuth().split("\\|")) {
                    if (!currentUserAuthor.contains(tmpStr)) {
                        isLegal = false;
                        break;
                    }
                }
                if (!isLegal) {
                    continue;
                }
            }
            //判断当前用户能否修改所选用户权限
            UserEntity user = userManagerService.findUserById(newAuth.getUserId());
//            if (!checkUpdateAuth(currentUser, user, resourceCommon)) {
//                continue;
//            }
            if (newAuth.getId() == null || newAuth.getId() == 0) {
                //新增的
                if (StringUtils.isEmpty(newAuth.getAuth())) {
                    continue;
                }
                try {
                    rangerService.setPermissionInRanger(type, resourceCommon.getContent(), newAuth.getAuth(), user.getName());
                    UserResourceRelationEntity entity = new UserResourceRelationEntity();
                    entity.setUserId(newAuth.getUserId());
                    entity.setAuthor(newAuth.getAuth());
                    entity.setResourceContent(resourceCommon.getContent());
                    entity.setResourceId(resourceId);
                    entity.setResourceType(type);
                    entity.setStatus(1);
                    entity.setResourceLevel(resourceCommon.getLevel());
                    entity.setInsDate(new Date());
                    userResRelationSerivce.save(entity);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                //修改的
                for (UserResourceRelationEntity oldAuth : oldList) {
                    if (!oldAuth.getUserId().equals(newAuth.getUserId())) {
                        continue;
                    }
                    if (newAuth.getAuth() == null) {
                        newAuth.setAuth("");
                    }
                    if (newAuth.getAuth().equalsIgnoreCase(oldAuth.getAuthor())) {
                        break;
                    }
                    deepUpdateAuthInfo(type, resourceCommon, oldAuth, newAuth, user);
                    break;
                }
            }
        }
    }

    /**
     * 级联管理权限
     *
     * @param type           资源类型
     * @param resourceCommon 资源信息
     * @param oldAuth        旧权限
     * @param newAuth        新权限
     * @param user           被修改权限人
     */
   // @Transactional
    private void deepUpdateAuthInfo(String type, ResourceCommonDTO resourceCommon, UserResourceRelationEntity oldAuth, AuthInfoVO newAuth, UserEntity user) {
        String[] oldAuthArray = oldAuth.getAuthor() == null ? new String[0] : oldAuth.getAuthor().split("\\|");
        String[] newAuthArray = newAuth.getAuth().split("\\|");
        List<String> deleteAuth = new ArrayList<>();
        for (String oldTmp : oldAuthArray) {
            boolean has = false;
            for (String newTmp : newAuthArray) {
                if (oldTmp.equalsIgnoreCase(newTmp)) {
                    has = true;
                    break;
                }
            }
            if (!has) {
                deleteAuth.add(oldTmp);
            }
        }
        //先修改当前用户的该资源权限
        try {
            rangerService.setPermissionInRanger(type, resourceCommon.getContent(), newAuth.getAuth(), user.getName());
            if (StringUtils.isEmpty(newAuth.getAuth())) {
                userResRelationSerivce.delete(oldAuth);
            } else {
                oldAuth.setAuthor(newAuth.getAuth());
                oldAuth.setUpdDate(new Date());
                userResRelationSerivce.save(oldAuth);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        //需要变更权限的用户id
        List<Integer> userIdList = new ArrayList<>();
        userIdList.add(user.getId());
        List<UserEntity> userList = userManagerService.findUsersByParentId(user.getId());
        if (userList != null && userList.size() > 0) {
            userIdList.addAll(userList.stream().map(u -> u.getId()).collect(Collectors.toList()));
        }
        //需要变更权限的资源id
        List<Integer> resourceIdList = new ArrayList<>();
        resourceIdList.add(resourceCommon.getId());
        int x = 0;
        int y = 0;
        while (x <= y) {
            List<Integer> ids = getResourceSonId(resourceIdList.get(x), type);
            if (ids != null && ids.size() != 0) {
                resourceIdList.addAll(ids);
                y += ids.size();
            }
            x++;
        }
        //获取哪些权限需要修改
        List<UserResourceRelationEntity> relationList = userResRelationSerivce.findByUserIdInAndResourceIdInAndResourceType(userIdList, resourceIdList, type);
        for (UserResourceRelationEntity tmp : relationList) {
            //如果是当前人和当前资源，之前已处理过了此处不处理
            if (user.getId().equals(tmp.getUserId()) && (resourceCommon.getId().equals(tmp.getResourceId())) && (type.equals(tmp.getResourceType()))) {
                continue;
            }
            //如果没权限可减就跳过
            if (StringUtils.isEmpty(tmp.getAuthor())) {
                continue;
            }
            String auth = tmp.getAuthor();
            StringBuffer newAuthString = new StringBuffer();
            String[] tmpAuth = auth.split("\\|");
            boolean hasChange = false;
            for (int i = 0; i < tmpAuth.length; i++) {
                boolean has = false;
                for (int j = 0; j < deleteAuth.size(); j++) {
                    if (tmpAuth[i].equalsIgnoreCase(deleteAuth.get(j))) {
                        has = true;
                        hasChange = true;
                        break;
                    }
                }
                if (!has) {
                    newAuthString.append(tmpAuth[i]).append("|");
                }
            }
            UserEntity tmpUser = userManagerService.findUserById(tmp.getUserId());
            if (tmpUser == null) {
                userResRelationSerivce.delete(oldAuth);
            } else {
                try {
                    if (hasChange) {
                        ResourceCommonDTO tmpResource = getResourceCommon(tmp.getResourceId(), tmp.getResourceType());
                        if (newAuthString.length() > 0) {
                            rangerService.setPermissionInRanger(type, tmpResource.getContent(), newAuthString.substring(0, newAuthString.length() - 1), tmpUser.getName());
                            tmp.setAuthor(newAuthString.substring(0, newAuthString.length() - 1));
                            tmp.setUpdDate(new Date());
                            userResRelationSerivce.save(tmp);
                        } else {
                            rangerService.setPermissionInRanger(type, tmpResource.getContent(), "", tmpUser.getName());
                            userResRelationSerivce.delete(tmp);

                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 查看是否可以修改权限
     *
     * @param currentUser    当前登录人
     * @param user           被修改人
     * @param resourceCommon 资源信息
     * @return 是否可以被修改
     */
    private boolean checkUpdateAuth(UserEntity currentUser, UserEntity user, ResourceCommonDTO resourceCommon) {
        if (currentUser == null || user == null) {
            return false;
        }
        if (currentUser.getId().equals(user.getId())) {
            return false;
        }
        if (RoleEnum.Admin.getValue().equals(user.getRole())) {
            return false;
        }
        if (RoleEnum.Tenant.getValue().equals(user.getRole()) && !currentUser.getId().equals(resourceCommon.getOwner())) {
            return false;
        }
        if (RoleEnum.User.getValue().equals(user.getRole()) && !currentUser.getId().equals(user.getParentId())) {
            return false;
        }
        return true;
    }

    /**
     * 获取资源信息通用
     *
     * @param resourceId 资源id
     * @param type       资源类型
     * @return 资源信息
     */
    private ResourceCommonDTO getResourceCommon(Integer resourceId, String type) {
        ResourceCommonDTO result = new ResourceCommonDTO();
        switch (type) {
            case "HDFS":
                HdfsResourceEntity hdfsEntity = hdfsResourceService.findHdfsResourceEntityById(resourceId);
                if (hdfsEntity == null) {
                    return null;
                } else {
                    result.setId(hdfsEntity.getId());
                    result.setContent(hdfsEntity.getUrl());
                    result.setLevel(hdfsEntity.getLevel());
                    result.setParentId(hdfsEntity.getParentId());
                    result.setOwner(hdfsEntity.getOwner());
                    return result;
                }
            case "HIVE":
                HiveResourceEntity hiveEntity = hiveResourceService.findHiveResourceEntityById(resourceId);
                if (hiveEntity == null) {
                    return null;
                } else {
                    String databaseName = hiveEntity.getDatabaseName();
                    String tableName = hiveEntity.getTableName();
                    String columnName = hiveEntity.getColumnName();
                    result.setContent(databaseName + "|" + (StringUtils.isEmpty(tableName) ? "*" : tableName) + "|" + (StringUtils.isEmpty(columnName) ? "*" : columnName));
                    result.setLevel(hiveEntity.getLevel());
                    result.setParentId(hiveEntity.getParentId());
                    result.setId(hiveEntity.getId());
                    result.setOwner(hiveEntity.getOwner());
                    return result;
                }
            case "HBASE":
                HbaseResourceEntity hbaseEntity = hbaseResourceService.findHbaseResourceEntityById(resourceId);
                if (hbaseEntity == null) {
                    return null;
                } else {
                    String spaceName = hbaseEntity.getSpaceName();
                    String tableName = hbaseEntity.getTableName();
                    String columnFamilyName = hbaseEntity.getColumnFamilyName();
                    String columnName = hbaseEntity.getColumnName();
                    result.setContent(spaceName + ":" + (StringUtils.isEmpty(tableName) ? "*" : tableName) + "|" + (StringUtils.isEmpty(columnFamilyName) ? "*" : columnFamilyName) + "|" + (StringUtils.isEmpty(columnName) ? "*" : columnName));
                    result.setLevel(hbaseEntity.getLevel());
                    result.setParentId(hbaseEntity.getParentId());
                    result.setId(hbaseEntity.getId());
                    result.setOwner(hbaseEntity.getOwner());
                    return result;
                }
            case "YARN":
                YarnResourceEntity yarnEntity = yarnResourceService.findYarnResourceEntityById(resourceId);
                if (yarnEntity == null) {
                    return null;
                } else {
                    if (yarnEntity.getLevel() == 2) {
                        YarnResourceEntity yarnParentEntity = yarnResourceService.findYarnResourceEntityById(yarnEntity.getParentId());
                        result.setContent(String.format("root.%s.%s", yarnParentEntity.getQueueName(), yarnEntity.getQueueName()));
                    } else {
                        result.setContent(String.format("root.%s", yarnEntity.getQueueName()));
                    }
                    result.setLevel(yarnEntity.getLevel());
                    result.setParentId(yarnEntity.getParentId());
                    result.setId(yarnEntity.getId());
                    result.setOwner(yarnEntity.getOwner());
                    return result;
                }
            case "KAFKA":
                KafkaResourceEntity kafkaEntity = kafkaResourceService.findKafkaResourceEntityById(resourceId);
                if (kafkaEntity == null) {
                    return null;
                } else {
                    result.setContent(kafkaEntity.getTopicName());
                    result.setLevel(kafkaEntity.getLevel());
                    result.setParentId(kafkaEntity.getParentId());
                    result.setId(kafkaEntity.getId());
                    result.setOwner(kafkaEntity.getOwner());
                    return result;
                }
        }
        return null;
    }

    /**
     * 获取资源的所有子资源id
     *
     * @param resourceId 资源id
     * @param type       资源类型
     * @return id的list
     */
    private List<Integer> getResourceSonId(Integer resourceId, String type) {
        ResourceCommonDTO result = new ResourceCommonDTO();
        switch (type) {
            case "HDFS":
                List<HdfsResourceEntity> hdfsList = hdfsResourceService.findByParentId(resourceId);
                if (hdfsList.size() > 0) {
                    return hdfsList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }

            case "HIVE":
                List<HiveResourceEntity> hiveList = hiveResourceService.findByParentId(resourceId);
                if (hiveList.size() > 0) {
                    return hiveList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "HBASE":
                List<HbaseResourceEntity> hbaseList = hbaseResourceService.findByParentId(resourceId);
                if (hbaseList.size() > 0) {
                    return hbaseList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "YARN":
                List<YarnResourceEntity> yarnList = yarnResourceService.findByParentId(resourceId);
                if (yarnList.size() > 0) {
                    return yarnList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
            case "KAFKA":
                List<KafkaResourceEntity> kafkaList = kafkaResourceService.findByParentId(resourceId);
                if (kafkaList.size() > 0) {
                    return kafkaList.stream().map(o -> o.getId()).collect(Collectors.toList());
                } else {
                    return null;
                }
        }
        return null;
    }

    /**
     * 获取租户列表或用户列表
     *
     * @param resourceId     资源id
     * @param type           资源类型
     * @param isTenantGetTen 是否是租户获取租户列表
     * @return
     */
    public List<UserAO> userList(Integer resourceId, String type, String username, boolean isTenantGetTen) {
        UserEntity user = AuthorizationHelper.getUser();
        ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
        //hdfs公共资源只能第一级获取租户
        if ("HDFS".equalsIgnoreCase(type) && RoleEnum.Admin.getValue().equals(user.getRole()) && (resourceCommon.getLevel() != 1 || resourceCommon.getOwner() != 1)) {
            return new ArrayList<>();
        }
        //hdfs私有资源只能第二级获取租户
        if ("HDFS".equalsIgnoreCase(type) && RoleEnum.Tenant.getValue().equals(user.getRole()) && isTenantGetTen && (resourceCommon.getLevel() != 2 || !resourceCommon.getOwner().equals(user.getId()))) {
            return new ArrayList<>();
        }
        Integer currentUserId = user.getId();
        if (isTenantGetTen) {
            user = userManagerService.findUserById(1);
        }
        List<UserEntity> userList = userManagerService.findUsersByParentId(user.getId());
        List<UserAO> result = new ArrayList<>();
        List<Integer> userIds = new ArrayList<>();
        boolean isEmpty = StringUtils.isEmpty(username);
        for (UserEntity tmp : userList) {
            if (!isEmpty) {
                if (!tmp.getName().contains(username)) {
                    continue;
                }
            }
            if (tmp.getId().equals(currentUserId)) {
                continue;
            }
            UserAO userAO = new UserAO();
            userAO.setUserId(tmp.getId());
            userAO.setUsername(tmp.getName());
            result.add(userAO);
            userIds.add(tmp.getId());
        }
        //判断资源链上是否已经有权限了
        // /a/b/c有权限，那就不能再赋权/a /a/b /a/b/c/d等
        List<Integer> resourceIds = new ArrayList<>();
        //广度优先搜索
        resourceIds.add(resourceCommon.getId());
        int x = 0;
        int y = 0;
        while (x <= y) {
            List<Integer> ids = getResourceSonId(resourceIds.get(x), type);
            if (ids != null && ids.size() != 0) {
                resourceIds.addAll(ids);
                y += ids.size();
            }
            x++;
        }
        ResourceCommonDTO tmpResource = getResourceCommon(resourceCommon.getParentId(), type);
        while (tmpResource != null) {
            resourceIds.add(tmpResource.getId());
            tmpResource = getResourceCommon(tmpResource.getParentId(), type);
        }
        List<UserResourceRelationEntity> relationList = userResRelationSerivce.findByUserIdInAndResourceIdInAndResourceType(userIds, resourceIds, type);
        List<UserAO> newResult = new ArrayList<>();
        for (UserAO tmp : result) {
            boolean has = false;
            for (UserResourceRelationEntity tmpRelation : relationList) {
                if (tmpRelation.getResourceId().equals(resourceId)) {
                    continue;
                }
                if (tmp.getUserId().equals(tmpRelation.getUserId())) {
                    has = true;
                    break;
                }
            }
            if (!has) {
                newResult.add(tmp);
            }
        }
        return newResult;
    }

    public String getSourceAuth(Integer resourceId, Integer userId, String type) {
        //获取当前用户的资源权限
        UserResourceRelationEntity currentUserResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceId, userId, type);

        ResourceCommonDTO resourceCommon = getResourceCommon(resourceId, type);
        if (resourceCommon == null) {
            return null;
        }
        while (currentUserResourceRelation == null) {
            resourceCommon = getResourceCommon(resourceCommon.getParentId(), type);
            if (resourceCommon == null) {
                break;
            }
            currentUserResourceRelation = userResRelationSerivce.findByResourceIdAndUserIdAndResourceType(resourceCommon.getId(), userId, type);
        }
        if (currentUserResourceRelation == null) {
            return null;
        } else {
            return currentUserResourceRelation.getAuthor();
        }
    }
}
